Considering the amount of work required to get ready to add a resource, you might think that creating a hierarchy and then performing so-called polymorphic queries is difficult. It isn't. The difficulty of moving towards supporting a hierarchy is that we started with a concrete class and wanted to later introduce an abstract concept, the Resource.
In this final step for the tutorial, we'll create a second kind of resource, a DVD and then write some basic tests.
Supporting DVD's
The first basic test is creating a dvd and checking it out to a Patron. This is a test we add to LibraryTest.java.
First test: Checkout a Dvd
@Test
publicvoid checkoutDvd(){final Patron p = createPatron();final Dvd d = createDvd();
library.checkout(p.getId(), CURRENT_DATE, d.getId());
assertTrue(d.isOnLoanTo(p));
assertEquals(CURRENT_PLUS_6, d.getDueDate());}private Dvd createDvd(){return library.createDvd("Raiders of the Lost Ark", newName("Steven",
"Spielberg"));}
This test uses a new constant, CURRENT_PLUS_6, here's the change to LibraryTest to support that.
To get this to compile, we need to add support in the library class for creating a DVD. Here's that basic support:
Updating Library
public Dvd createDvd(finalString title, finalName directorsName){final Director director = new Director();
director.setName(directorsName);final Dvd d = new Dvd();
d.setTitle(title);
d.setDirector(director);
getResourceDao().create(d);return d;}
Notice that we have a director and a dvd in this example. Here are those classes: Director.java
packageentity;importjava.util.Calendar;importjava.util.Date;importjavax.persistence.CascadeType;importjavax.persistence.Entity;importjavax.persistence.ManyToOne;/**
* Notice that to get this to "work" all we need to do is inherit from Resource.
* As with book, we do not define an id field, since it is inherited.
*
* The way this class is represented in the database is determined by meta
* information in the Resource base class.
*
* Of course, regular Java rules apply here. The Resource base class defines 2
* abstract methods, both of which are overridden here.
*/
@Entitypublicclass Dvd extends Resource {
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST})private Director director;
@OverridepublicDate calculateDueDateFrom(finalDate checkoutDate){finalCalendar c = Calendar.getInstance();
c.setTime(checkoutDate);
c.add(Calendar.DATE, 6);return c.getTime();}
@Overridepublicdouble calculateFine(finalint daysLate){if(daysLate <5){return .3 * daysLate;}if(daysLate <10){return .6 * daysLate;}return6.0;}public Director getDirector(){return director;}publicvoid setDirector(Director director){this.director = director;}}
Resource.java
To get this to actually work, we need to use the @Inheritance annotation on resource. Here's the change:
As mentioned before, there are three kinds of representations for hierarchy. We are using the so-called JOINED approach, which means there is a table per class. It turns out that we need to use this approach based on how we've defined Book. Why that is will be answered in a following assignment.
A Few More Tests
Here are a few more tests to verify basic functionality. These also belong in LibraryTest.java.
@Test
publicvoid returnDvdLate(){final Dvd d = createDvd();final Patron p = createPatron();
library.checkout(p.getId(), CURRENT_DATE, d.getId());
library.returnResource(CURRENT_PLUS_8, d.getId());
assertEquals(1, p.getFines().size());
assertEquals(0.6d, p.calculateTotalFines());}
@Test
publicvoid checkoutDvdAndBook(){final Dvd d = createDvd();finalBook b = createBook();final Patron p = createPatron();
library.checkout(p.getId(), CURRENT_DATE, d.getId());
library.checkout(p.getId(), CURRENT_DATE, b.getId());finalList<Resource> list = library.listResourcesOnLoanTo(p.getId());
assertEquals(2, list.size());
assertTrue(d.isOnLoanTo(p));
assertTrue(b.isOnLoanTo(p));}
Summary: Inheritance
That's pretty much it. If we had started with a base class called Resource, this work would have been trivial. Adding new subclasses is quite easy. Figuring out which representation may take a little experimentation, but it's easy to change.
Queries are inherently polymorphic in nature if that makes sense for the given query. Your challenge is working with a base type insead of down-casting to a derived type.
In this final step for the tutorial, we'll create a second kind of resource, a DVD and then write some basic tests.
Supporting DVD's
The first basic test is creating a dvd and checking it out to a Patron. This is a test we add to LibraryTest.java.First test: Checkout a Dvd
@Test public void checkoutDvd() { final Patron p = createPatron(); final Dvd d = createDvd(); library.checkout(p.getId(), CURRENT_DATE, d.getId()); assertTrue(d.isOnLoanTo(p)); assertEquals(CURRENT_PLUS_6, d.getDueDate()); } private Dvd createDvd() { return library.createDvd("Raiders of the Lost Ark", new Name("Steven", "Spielberg")); }This test uses a new constant, CURRENT_PLUS_6, here's the change to LibraryTest to support that.To get this to compile, we need to add support in the library class for creating a DVD. Here's that basic support:
Updating Library
Notice that we have a director and a dvd in this example. Here are those classes:
Director.java
Dvd.java
Resource.java
To get this to actually work, we need to use the @Inheritance annotation on resource. Here's the change:
As mentioned before, there are three kinds of representations for hierarchy. We are using the so-called JOINED approach, which means there is a table per class. It turns out that we need to use this approach based on how we've defined Book. Why that is will be answered in a following assignment.
A Few More Tests
Here are a few more tests to verify basic functionality. These also belong in LibraryTest.java.
@Test public void returnDvdLate() { final Dvd d = createDvd(); final Patron p = createPatron(); library.checkout(p.getId(), CURRENT_DATE, d.getId()); library.returnResource(CURRENT_PLUS_8, d.getId()); assertEquals(1, p.getFines().size()); assertEquals(0.6d, p.calculateTotalFines()); } @Test public void checkoutDvdAndBook() { final Dvd d = createDvd(); final Book b = createBook(); final Patron p = createPatron(); library.checkout(p.getId(), CURRENT_DATE, d.getId()); library.checkout(p.getId(), CURRENT_DATE, b.getId()); final List<Resource> list = library.listResourcesOnLoanTo(p.getId()); assertEquals(2, list.size()); assertTrue(d.isOnLoanTo(p)); assertTrue(b.isOnLoanTo(p)); }Summary: Inheritance
That's pretty much it. If we had started with a base class called Resource, this work would have been trivial. Adding new subclasses is quite easy. Figuring out which representation may take a little experimentation, but it's easy to change.Queries are inherently polymorphic in nature if that makes sense for the given query. Your challenge is working with a base type insead of down-casting to a derived type.